#include "GraficaSim.h"
#include <stdio.h>
#include <string.h>

GraficaSim::GraficaSim(Simulacion *s){


  /*Inicializa la libreraia*/   	
 g_thread_init (NULL);
 gdk_threads_init ();
 gdk_threads_enter ();
 gtk_init (NULL,NULL);
	
 
  /*Inicializa la matriz del campo*/	
  for(int i=0;i<20;i++)
	 for(int j=0;j<15;j++){
	     campo[i][j]=0;
	     crecimiento[i][j]=0;
	     degradacion[i][j]=0;
	 }
	 
   pixmap=NULL;
   mensajeSalida=NULL;	 
	
   sim=s;
   hayConexion=false;
   seCargoCampo=false;
   haySimulacion =false;	 
   velocidad=0;	 
	 	 
  /*Crea la ventana*/
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Simulador");	
  gtk_window_set_default_size(GTK_WINDOW(window),880,550);
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
  
	 
  /*Funcion  que se llama al cerrar la ventana*/	
  gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);  
   gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC(callback_delete_event ), this);  

  /*Crea Contenedor horizontal*/
  hbox = gtk_hbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), hbox);
  gtk_widget_show (hbox);
   /*Crea Contenedor verical*/
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (hbox), vbox);
  gtk_widget_show (vbox);	 

 /*Crea frame del Campo*/
 frameCampo=gtk_frame_new( "Campo"); 
 gtk_box_pack_start (GTK_BOX (hbox), frameCampo, TRUE, TRUE, 10);
 gtk_frame_set_shadow_type( GTK_FRAME(frameCampo), GTK_SHADOW_ETCHED_OUT);
 gtk_widget_show(frameCampo);

 /* Crear la zona de dibujado */
  drawing_area = gtk_drawing_area_new ();
  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 32*20, 15*32);
  gtk_container_add (GTK_CONTAINER (frameCampo), drawing_area);
  gtk_widget_show (drawing_area); 
 
 /*Tooltip*/
  gTimer=g_timer_new(); 
  pLayout=gtk_widget_create_pango_layout(drawing_area," ");	 
  timerOn=false;
  posX=0;posY=0;	
  tiempo=0;	 
  	 

 /*Crea el frame de las herramientas*/
 gtk_box_pack_start (GTK_BOX (vbox), creaFrameConfiguracion(), TRUE, TRUE, 5);
 gtk_box_pack_start (GTK_BOX (vbox), creaFrameOpciones(), TRUE, TRUE, 5);
 gtk_box_pack_start (GTK_BOX (vbox), creaFrameStatus(), TRUE, TRUE, 5);


 setCallbacks(); 
 gtk_widget_show (window);

}

void GraficaSim::comenzar(){
	
	gtk_main ();	
	gdk_threads_leave ();
}

void GraficaSim:: setCallbacks(){

  /* Las señales utilizadas para manejar el backing pixmap */
  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
                      (GtkSignalFunc) callback_expose_event,  this );
  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
                      (GtkSignalFunc) callback_configure_event, this);            

  /* Señales evento */

  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
                      (GtkSignalFunc) callback_motion_notify_event, this);

  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK|GDK_ENTER_NOTIFY_MASK
                         | GDK_LEAVE_NOTIFY_MASK
                         | GDK_POINTER_MOTION_MASK
                         | GDK_POINTER_MOTION_HINT_MASK);

 
}

GtkWidget * GraficaSim::creaFrameOpciones(){
	
	
  GtkWidget *frame;
  GtkWidget *bbox;
  GtkWidget *boton;

  /*Crea un frame*/
  frame = gtk_frame_new ("Opciones");
  /*Crea contenedor de botones*/
  bbox = gtk_vbutton_box_new ();
   
  gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
  gtk_container_add (GTK_CONTAINER (frame), bbox);

  /* Establece la apariencia de la Caja de Botones */
  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox),GTK_BUTTONBOX_SPREAD);
  gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 0);
  
  boton = gtk_button_new_with_label ("Iniciar");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (apretarBotonIniciar),this);		 
  
  boton = gtk_button_new_with_label ("Reiniciar");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (apretarBotonReiniciar),this);		 
	
  boton = gtk_button_new_with_label ("Detener");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (apretarBotonDetener),this);	
      
  boton = gtk_button_new_with_label (" +2X");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (apretarBotonMas2x),this);	
  
  boton = gtk_button_new_with_label ("-2X");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked",  (GtkSignalFunc) (apretarBotonMenos2x),this);	
  
  gtk_widget_show_all (frame);
  return(frame);

}

GtkWidget * GraficaSim::creaFrameStatus(){
		
  GtkWidget *frame;
  GtkWidget *vbox;
 
  /*Crea un frame*/
  frame = gtk_frame_new ("Status");
  status= gtk_entry_new( );
  /*Crea Contenedor horizontal*/
  vbox = gtk_vbox_new (FALSE, 5);
  gtk_container_add (GTK_CONTAINER (frame), vbox);
  gtk_widget_show (vbox);	
  gtk_container_add (GTK_CONTAINER (vbox), status);
  gtk_widget_show_all (frame);
  return(frame);	
	
}

GtkWidget * GraficaSim::creaFrameConfiguracion (){

    GtkWidget *frame;
    GtkWidget *bbox;
    GtkWidget *vbox;
    GtkWidget *boton;
    GtkWidget *  labelIP;
  
  /*Crea un frame*/
  frame = gtk_frame_new ("Configuracion");
 
  /*Crea Contenedor horizontal*/
  vbox = gtk_vbox_new (FALSE, 5);
  gtk_container_add (GTK_CONTAINER (frame), vbox);
  gtk_widget_show (vbox);	
	
  labelIP=gtk_label_new( "Direccion ip"); 
  gtk_container_add (GTK_CONTAINER (vbox), labelIP);	
  /*Creo entrada del puerto*/
  entradaIP= gtk_entry_new(  );
  gtk_entry_set_text( GTK_ENTRY(entradaIP),"127.0.0.1");
  gtk_container_add (GTK_CONTAINER (vbox), entradaIP);
	
  labelIP=gtk_label_new( "Puerto"); 
  gtk_container_add (GTK_CONTAINER (vbox), labelIP);	
  /*Creo entrada del puerto*/
  entradaPuerto= gtk_entry_new( );
  gtk_container_add (GTK_CONTAINER (vbox), entradaPuerto);	
 
  /*Crea contenedor de botones*/
  bbox = gtk_vbutton_box_new ();
  gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
  gtk_container_add (GTK_CONTAINER (vbox), bbox);
  
  boton = gtk_button_new_with_label ("Conectar");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (apretarBotonConectar),this);		 
 
  boton = gtk_button_new_with_label ("Cargar Campo");
  gtk_container_add (GTK_CONTAINER (bbox), boton);
  /*Accion del boton al clickear*/
  gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (apretarBotonAbrir),this);		 
 
 
   gtk_widget_show_all (frame);
   return frame;
}

gboolean GraficaSim::expose_event (GtkWidget *widget, GdkEventExpose *event){
    
	gdk_draw_pixmap(widget->window,
                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                  pixmap,
                  event->area.x, event->area.y,
                  event->area.x, event->area.y,
                  event->area.width, event->area.height);

  return FALSE;
 
}



gboolean GraficaSim:: motion_notify_event (GtkWidget *widget, GdkEventMotion *event){
 
  int x, y;
  GdkModifierType state;
	    
  if (event->is_hint)
    		gdk_window_get_pointer (event->window, &x, &y, &state);
  else
    {
      	x = (int)event->x;
      	y = (int)event->y;
      	state = (GdkModifierType)event->state;
    }
    
	if(  (posX==(int)x/32)&& (posY==(int)y/32) ){
	    g_timer_elapsed(gTimer,&tiempo);
        	if( tiempo>450000){
			  posX= (int) x/32;
	                  posY=(int)y/32;
		    	  timerOn=true;
		}
		       
   }  
   else{
        g_timer_reset( gTimer);
        posX= (int) x/32;
        posY=(int)y/32;
	timerOn=false;
	tiempo=0;
   }	    
      
       return TRUE;
}

gboolean GraficaSim::configure_event (GtkWidget *widget, GdkEventConfigure *event){

  if (pixmap)
    gdk_pixmap_unref(pixmap);

   pixmap = gdk_pixmap_new(widget->window,
                          widget->allocation.width,
                          widget->allocation.height,
                          -1);
  gdk_draw_rectangle (pixmap,
                      widget->style->white_gc,
                      TRUE,
                      0, 0,
                      widget->allocation.width,
                      widget->allocation.height);
  
  dibujaCampo(widget);
  return TRUE;
}


GdkGC*  GraficaSim:: setColor(GtkWidget* widget,int red, int green, int blue){
	
  GdkColor color;
  GdkGC *gc;
  
  /* Crea un contexto grafico */
  gc = gdk_gc_new(widget->window);
 
  /*Setea lo valore RGB del color*/ 
   color.red = red * (65535/255);
   color.green = green*(65535/255);
   color.blue = blue*(65535/255);
   /*Aloca el color*/
   gdk_colormap_alloc_color(gtk_widget_get_colormap(widget),&color, TRUE,TRUE);
   gdk_gc_set_foreground(gc, &color);
   return gc;
  
}
void GraficaSim:: dibujaCampo(GtkWidget *widget){
  
  /*Punto de inicio*/
  gint i=10;
 /*gint j=10; */
	
 dibujarParcelas(widget);	
 gdk_draw_line (pixmap,widget->style->black_gc,10,10,10,490); /*v izquierda*/
 gdk_draw_line (pixmap,widget->style->black_gc,10,10,650,10); /*H arriba*/
 gdk_draw_line (pixmap,widget->style->black_gc,10,490,650,490); /*H abajo*/
 gdk_draw_line (pixmap,widget->style->black_gc,650,10,650,490); /*v derecha*/
 
/*Lineas verticales*/
 for(i=0;i<20;i++)
    gdk_draw_line (pixmap,widget->style->black_gc,10+i*32,10,10+i*32,490);	
 /*Lineas horizontales*/
  for(i=0;i<15;i++)
     gdk_draw_line (pixmap,widget->style->black_gc,10,10+i*32,650,10+i*32); 	
  
 if(timerOn == true)  dibujarToolTip(widget,posX,posY);

}

void GraficaSim::dibujarToolTip (GtkWidget *widget, int x, int y){
   	
	int coorX= x;
	int coorY= y;
        int ajusteX=0;
	int ajusteY=0;
	GdkGC *gc;
	
	   /*Calcula la informacion a mostrar*/
       char lon [255];
       std::string linea;
	   if (campo[posX][posY] ==2 )
	 	  linea.assign("Maiz");
	   if (campo[posX][posY] ==3 )
	 	  linea.assign("Girasol");
	   if (campo[posX][posY] ==4 )
	 	  linea.assign("Soja");
	   
	   sprintf(lon, " X :%d  Y :%d\n %s\n EM: %d\n D: %d", posX,posY,linea.c_str(),crecimiento[posX][posY] /100,(int)degradacion[posX][posY]);
	   pango_layout_set_text(pLayout,lon,-1);  
		
	  /*Ajustes*/
	   if(coorX==19)
		ajusteX= -30;
	   if(coorX==0)
		ajusteX= 10;
	   if(coorY==14)
		ajusteY=-25;
	   if(coorY==0)
		ajusteY=10;
	   
	   gc=setColor(widget,255,255,0);
	   gdk_draw_rectangle(pixmap ,gc, 1, coorX*32+ajusteX, coorY*32+ajusteY ,80 , 70);
	   gdk_draw_layout (pixmap,widget->style->black_gc,coorX*32+ajusteX,coorY*32+ajusteY,pLayout);
}

void GraficaSim::dibujarParcelas(GtkWidget *widget){
	
	GdkGC*  gc;
	for(int i=0;i<20;i++)
	   for(int j=0;j<15;j++){
	
	        /*Parcela vacia  BLANCA*/
		if(campo[i][j]==0){
			gc=setColor(widget,255,255,255);	}
		/*Sin plantar Marron*/
	        if(campo[i][j]==1)
			gc=setColor(widget,120,120,0);	
				
		/*Maiz  Amarillo*/
	        if(campo[i][j]==2){
		         gc=setColor(widget,0,0,(crecimiento[i][j]*255)/10000);	
		}	
		/*Girasol naranja*/
	        if(campo[i][j]==3)
		         gc=setColor(widget,(crecimiento[i][j]*255)/10000,0,0);	
		/*Soja Rojo*/
	        if(campo[i][j]==4)
		         gc=setColor(widget,0,(crecimiento[i][j]*255)/10000,0);	
			
	       gdk_draw_rectangle(pixmap, gc, 1,10+i*32,10+j*32 ,32 , 32);
	}	
	
}

void GraficaSim::redibujar(int x, int y){
	
    GdkRectangle update_rect;
    update_rect.x =x;
    update_rect.y =y;
    update_rect.width = 32*20;
    update_rect.height =32*15;
    gtk_widget_draw (drawing_area, &update_rect);
	
	
}
void GraficaSim::redibujar(int x, int y ,int ancho,int largo){

    GdkRectangle update_rect;
    update_rect.x =(32*x)+10;
    update_rect.y =(32*y)+10;
    update_rect.width = ancho;
    update_rect.height =largo;
    gtk_widget_draw (drawing_area, &update_rect);
	
}

void GraficaSim::actualizarEstado(){
		
    sim->devolverValoresCrecimiento(crecimiento);
    sim->devolverValoresDegradacion(degradacion);
    dibujaCampo(drawing_area);
    redibujar(0,0,32*20,32*15);
		
}
void GraficaSim::abrirArchivo(){
	
	fileSelector=gtk_file_selection_new( "Abrir achivo" );
	gtk_signal_connect (GTK_OBJECT (fileSelector), "destroy", (GtkSignalFunc) gtk_widget_destroy,
       GTK_OBJECT (fileSelector));
    /* Conectar el ok_button con la función file_ok_sel*/ 
    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSelector)->ok_button),
			"clicked", (GtkSignalFunc) file_ok_boton_Abrir, this );
    
    /* Conectar el cancel_button con la destrucción del widget */
    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (fileSelector)->cancel_button),
			       "clicked", (GtkSignalFunc) gtk_widget_destroy,
			       GTK_OBJECT (fileSelector));
	
	gtk_widget_show(fileSelector);
}

void GraficaSim::abrir(){
	 
	g_print ("Abrir Archivo : %s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fileSelector)));
	sim->cargarCampo(gtk_file_selection_get_filename (GTK_FILE_SELECTION (fileSelector)),campo);
	gtk_widget_destroy(fileSelector);
	seCargoCampo=true;
	dibujaCampo(drawing_area);
	redibujar(0,0);
}

void GraficaSim:: conectar(){
	
  if(sim->conectar(gtk_entry_get_text( GTK_ENTRY(entradaIP)),atoi(gtk_entry_get_text( GTK_ENTRY(entradaPuerto))) )){	
		 g_print ("Conectadose a Ip : %s   Puerto : %s\n", gtk_entry_get_text( GTK_ENTRY(entradaIP)),gtk_entry_get_text( GTK_ENTRY(entradaPuerto)));
	 	hayConexion=true; 
 	 	gtk_entry_set_text(GTK_ENTRY(status),"Conectado");	
  }
  else
	   gtk_entry_set_text(GTK_ENTRY(status),"Error Conexion");	
}

void GraficaSim::iniciar(){
	
	if(hayConexion && seCargoCampo){
			sim->iniciar();
			gtk_entry_set_text(GTK_ENTRY(status),"Simulacion iniciada");	
		    haySimulacion=true;
	}	
	else
		gtk_entry_set_text(GTK_ENTRY(status),"Error conexion/carga");	
}

void GraficaSim::reiniciar(){
	
	sim->reiniciar();
	 gtk_entry_set_text(GTK_ENTRY(status),"Simulacion reiniciada");	
}

void GraficaSim::detener(){
	 sim->detener();
	 hayConexion=false; 
	 haySimulacion=false;
	 gtk_entry_set_text(GTK_ENTRY(status),"Simulacion Detenida");	
}

void GraficaSim::subirVelocidad(){
	
	if(!haySimulacion){
		gtk_entry_set_text(GTK_ENTRY(status),"Debe iniciar una simulacion");
        return;		
	}
		
  	char text[20];
	
   	if(velocidad <6)
			velocidad=velocidad+2;
	sim->subirVelocidad();
    sprintf(text, "Velocidad %dx",velocidad);
	gtk_entry_set_text(GTK_ENTRY(status),text);	
}
void GraficaSim::bajarVelocidad(){
	
	if(!haySimulacion){
		gtk_entry_set_text(GTK_ENTRY(status),"Debe iniciar una simulacion");
        return;		
	}
	char text[20];
	
   	if(velocidad >=2)
			velocidad=velocidad-2;
	sim->bajarVelocidad();
	 sprintf(text, "Velocidad %dx",velocidad);
	gtk_entry_set_text(GTK_ENTRY(status),text);	

}

void GraficaSim::simulacionEnCurso(){
	  
		 if(haySimulacion==false){
				gtk_main_quit();			 
		    	 return ;
		 } 
		     
		 mensajeSalida = gtk_dialog_new ();
         GtkWidget *etiqueta = gtk_label_new ("Existe una simulacion en curso. Realmente quiere salir ?");
		 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (mensajeSalida)->vbox), etiqueta, TRUE, TRUE, 0);
	
         GtkWidget *boton = gtk_button_new_with_label ("Si");
   		 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (mensajeSalida)->vbox), boton, TRUE, TRUE, 0);
  		 /*Accion del boton al clickear*/
    	 gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (gtk_main_quit),this);		 
	 	 boton = gtk_button_new_with_label ("No");
   		 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (mensajeSalida)->vbox), boton, TRUE, TRUE, 0);
   		/*Accion del boton al clickear*/
         gtk_signal_connect (GTK_OBJECT (boton), "clicked", (GtkSignalFunc) (salir_boton_no),this);		  
    
	   	gtk_widget_show_all(mensajeSalida);
		
}


void GraficaSim::destruirVentana(){
	
	gtk_widget_destroy(mensajeSalida);
}

void GraficaSim::quit () {  
	gtk_exit (0); 
}

GraficaSim::~GraficaSim(){
	g_timer_destroy(gTimer);
	quit();
}
